class EthernetPkt:
    def __init__(self):
        self.time = ''
        self.dst = ''
        self.src = ''
        self.type_ = ''
        
    def PrintMyInfo(self):
        print("EthernetInfo: ")
        print("time:    %s" %(self.time))
        print("dst:     %s" %(self.dst))
        print("src:     %s" %(self.src))
        print("type:    %s" %(self.type_))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'dst':
            return self.dst
        elif fieldname == 'src':
            return self.src
        elif fieldname == 'type':
            return self.type_
        else:
            print("EthernetPkt does not have field named %s !" %fieldname)

class Ipv4Pkt:
    def __init__(self):
        self.time = ''
        self.version = 0        #版本号
        self.headerLen = 0      #头部长度
        self.tos = 0            #服务类型
        self.packetLen = 0      #总长度
        self.protoId = 0        #标识
        self.flags = ''         #分片标志
        self.frag = 0           #片偏移
        self.ttl = 0            #生存周期
        self.proto = ''         #上层协议，1:ICMP,2:IGMP,6:TCP,17:UDP,89:OSPF
        self.chksum = 0         #校验和，这里直接存储转换成十进制之后的值
        self.srcIp = ''         #源IP地址
        self.dstIp = ''         #目的IP地址
        
    def PrintMyInfo(self):
        print("IpInfo: ")
        print("time:      %s" %(self.time))
        print("version:   %d" %(self.version))
        print("headerLen: %d" %(self.headerLen))
        print("tos:       %d" %(self.tos))
        print("packetLen: %d" %(self.packetLen))
        print("protoId:   %d" %(self.protoId))
        print("flags:     %s" %(self.flags))
        print("frag:      %d" %(self.frag))
        print("ttl:       %d" %(self.ttl))
        print("proto:     %s" %(self.proto))
        print("chksum:    %d" %(self.chksum))
        print("srcIp:     %s" %(self.srcIp))
        print("dstIp:     %s" %(self.dstIp))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'version':
            return self.version
        elif fieldname == 'headerLen':
            return self.headerLen
        elif fieldname == 'tos':
            return self.tos
        elif fieldname == 'packetLen':
            return self.packetLen
        elif fieldname == 'protoId':
            return self.protoId
        elif fieldname == 'flags':
            return self.flags
        elif fieldname == 'frag':
            return self.frag
        elif fieldname == 'ttl':
            return self.ttl
        elif fieldname == 'proto':
            return self.proto
        elif fieldname == 'chksum':
            return self.chksum
        elif fieldname == 'srcIp':
            return self.srcIp
        elif fieldname == 'dstIp':
            return self.dstIp
        else:
            print("Ipv4Pkt does not have field named %s !" %fieldname)
        
class Ipv6Pkt:
    def __init__(self):
        self.time = ''
        self.version = 0     #版本号
        self.tc = 0          #流量类别
        self.fl = 0          #流标签
        self.plen = 0        #载荷长度
        self.nh = ''         #下一报文头
        self.hlim = 0        #跳数限制
        self.srcIp = ''      #源IP地址
        self.dstIp = ''      #目的IP地址
        
    def PrintMyInfo(self):
        print("IpInfo: ")
        print("time:      %s" %(self.time))
        print("version:   %d" %(self.version))
        print("tc:        %d" %(self.tc))
        print("fl:        %d" %(self.fl))
        print("plen:      %d" %(self.plen))
        print("nh:        %s" %(self.nh))
        print("hlim:      %d" %(self.hlim))
        print("srcIp:     %s" %(self.srcIp))
        print("dstIp:     %s" %(self.dstIp))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'version':
            return self.version
        elif fieldname == 'tc':
            return self.tc
        elif fieldname == 'fl':
            return self.fl
        elif fieldname == 'plen':
            return self.plen
        elif fieldname == 'nh':
            return self.nh
        elif fieldname == 'hlim':
            return self.hlim
        elif fieldname == 'srcIp':
            return self.srcIp
        elif fieldname == 'dstIp':
            return self.dstIp
        else:
            print("Ipv6Pkt does not have field named %s !" %fieldname)
    
class TcpPkt:
    def __init__(self):
        self.sport = ''      #源端口
        self.dport = ''      #目的端口
        self.seq = 0         #序列号
        self.ack = 0         #确认号
        self.dataofs = 0     #数据偏移
        self.reserved = 0    #保留
        self.flags = ''      #标志位
        self.window = 0      #窗口大小
        self.chksum = 0      #校验和，这里直接存储转换成十进制之后的值
        self.urgptr = 0      #紧急指针
        self.raw = ''
        
    def PrintMyInfo(self):
        print("TcpInfo: ")
        print("time:     %s" %(self.time))
        print("sport:    %s" %(self.sport))
        print("dport:    %s" %(self.dport))
        print("seq:      %d" %(self.seq))
        print("ack:      %d" %(self.ack))
        print("dataofs:  %d" %(self.dataofs))
        print("reserved: %d" %(self.reserved))
        print("flags:    %s" %(self.flags))
        print("window:   %d" %(self.window))
        print("chksum:   %d" %(self.chksum))
        print("urgptr:   %d" %(self.urgptr))
        print("raw:      %s" %(self.raw))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'sport':
            return self.sport
        elif fieldname == 'dport':
            return self.dport
        elif fieldname == 'seq':
            return self.seq
        elif fieldname == 'ack':
            return self.ack
        elif fieldname == 'dataofs':
            return self.dataofs
        elif fieldname == 'reserved':
            return self.reserved
        elif fieldname == 'flags':
            return self.flags
        elif fieldname == 'window':
            return self.window
        elif fieldname == 'chksum':
            return self.chksum
        elif fieldname == 'urgptr':
            return self.urgptr
        elif fieldname == 'raw':
            return self.raw
        else:
            print("TcpPkt does not have field named %s !" %fieldname)

class UdpPkt:
    def __init__(self):
        self.time = ''
        self.sport = ''    #源端口
        self.dport = ''    #目的端口
        self.packetLen = 0 #报文长度
        self.chksum = 0    #校验和，这里直接存储转换成十进制之后的值
        
    def PrintMyInfo(self):
        print("UdpInfo: ")
        print("time:      %s" %(self.time))
        print("sport:     %s" %(self.sport))
        print("dport:     %s" %(self.dport))
        print("packetLen: %d" %(self.packetLen))
        print("chksum:    %d" %(self.chksum))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'sport':
            return self.sport
        elif fieldname == 'dport':
            return self.dport
        elif fieldname == 'packetLen':
            return self.packetLen
        elif fieldname == 'chksum':
            return self.chksum
        else:
            print("UdpPkt does not have field named %s !" %fieldname)
        
class ArpPkt:
    def __init__(self):
        self.time = ''
        self.hwtype = ''  #硬件类型
        self.ptype = ''   #协议类型
        self.hwlen = 0    #硬件地址长度
        self.plen = 0     #协议长度
        self.op = ''      #操作类型
        self.hwsrc = ''   #源MAC地址
        self.psrc = ''    #源IP地址
        self.hwdst = ''   #目的MAC地址
        self.pdst = ''    #目的IP地址
        
    def PrintMyInfo(self):
        print("ArpInfo: ")
        print("time:   %s" %(self.time))
        print("hwtype: %s" %(self.hwtype))
        print("ptype:  %s" %(self.ptype))
        print("hwlen:  %d" %(self.hwlen))
        print("plen:   %d" %(self.plen))
        print("op:     %s" %(self.op))
        print("hwsrc:  %s" %(self.hwsrc))
        print("psrc:   %s" %(self.psrc))
        print("hwdst:  %s" %(self.hwdst))
        print("pdst:   %s" %(self.pdst))
        print("\n")
    
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'hwtype':
            return self.hwtype
        elif fieldname == 'ptype':
            return self.ptype
        elif fieldname == 'hwlen':
            return self.hwlen
        elif fieldname == 'plen':
            return self.plen
        elif fieldname == 'op':
            return self.op
        elif fieldname == 'hwsrc':
            return self.hwsrc
        elif fieldname == 'psrc':
            return self.psrc
        elif fieldname == 'hwdst':
            return self.hwdst
        elif fieldname == 'pdst':
            return self.pdst
        else:
            print("TcpPkt does not have field named %s !" %fieldname)
    
class DnsPkt:
    def __init__(self):
        self.time = ''
        self.id = 0         #事务ID
        self.flags = {}     #标志，len(flags)=10,flags=[qr,opcode,aa,tc,rd,ra,z,ad,cd,rcode]
        self.qdcount = 0    #问题计数
        self.ancount = 0    #回答资源记录数
        self.nscount = 0    #权威名称服务器计数
        self.arcount = 0    #附加资源记录数
        self.qdarea = {}    #查询问题区域，len(qdarea)=qdcount，注：因为通常问题数都为1，所以这里暂时只支持一个问题的存储，如果有需要后续再更改
        self.anarea = []    #回答问题区域，len(anarea)=ancount，每个元素是一个字典
        self.nsarea = []    #权威名称服务器区域，ken(nsarea)=nscount，每个元素是一个字典
        self.ararea = []    #附加信息区域，len(ararea)=arcount，每个元素是一个字典
        
    def PrintMyInfo(self):
        print("DnsInfo: ")
        print("time:    %s" %(self.time))
        print("id:      %s" %(self.id))
        print("flags:  ",  self.flags)
        print("qdcount: %d" %(self.qdcount))
        print("ancount: %d" %(self.ancount))
        print("nscount: %d" %(self.nscount))
        print("arcount: %d" %(self.arcount))
        print("qdarea: ", self.qdarea)
        print("anarea: ", self.anarea)
        print("nsarea: ", self.nsarea)
        print("ararea: ", self.ararea)
        print("\n")
        
    def GetSingleField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'id':
            return self.id
        #flags = qr,opcode,aa,tc,rd,ra,z,ad,cd,rcode
        elif fieldname == 'qr':
            return self.flags[0]
        elif fieldname == 'opcode':
            return self.flags[1]
        elif fieldname == 'aa':
            return self.flags[2]
        elif fieldname == 'tc':
            return self.flags[3]
        elif fieldname == 'rd':
            return self.flags[4]
        elif fieldname == 'ra':
            return self.flags[5]
        elif fieldname == 'z':
            return self.flags[6]
        elif fieldname == 'ad':
            return self.flags[7]
        elif fieldname == 'cd':
            return self.flags[8]
        elif fieldname == 'rcode':
            return self.flags[9]
        elif fieldname == 'qdcount':
            return self.qdcount
        elif fieldname == 'ancount':
            return self.ancount
        elif fieldname == 'nscount':
            return self.nscount
        elif fieldname == 'arount':
            return self.arcount
        elif fieldname == 'qd':
            return self.qdarea
        elif fieldname == 'hwdst':
            return self.hwdst
        elif fieldname == 'pdst':
            return self.pdst
        else:
            print("DnsPkt does not have field named %s !" %fieldname)
        
    # def GetTime(self):
    #     return self.time
        
    # def GetId(self):
    #     return self.id
    
    # def GetQr(self):  #qr,opcode,aa,tc,rd,ra,z,ad,cd,rcode
    #     return self.flags[0]
    
    # def GetOpcode(self):
    #     return self.flags[1]
    
    # def GetAa(self):
    #     return self.flags[2]
    
    # def GetTc(self):
    #     return self.flags[3]
    
    # def GetRd(self):
    #     return self.flags[4]
    
    # def GetRa(self):
    #     return self.flags[5]
    
    # def GetZ(self):
    #     return self.flags[6]
    
    # def GetAd(self):
    #     return self.flags[7]
    
    # def GetCd(self):
    #     return self.flags[8]
    
    # def GetRcode(self):
    #     return self.flags[9]
    
    # def GetQdcount(self):
    #     return self.qdcount
    
    # def GetAncount(self):
    #     return self.ancount
    
    # def GetNscount(self):
    #     return self.nscount
    
    # def GetArcount(self):
    #     return self.arcount
    
    # #注：因为通常问题数都为1，所以这里暂时只支持一个问题的存储，如果有需要后续再更改
    # def GetQd(self):
    #     return self.qdarea       #字典
    
    # def GetQd(self, index):    #获取第index个问题
    #     if index >= self.qdcount:
    #         print("This dns packet has only %d queries!" %(self.qdcount))
    #         return
    #     return self.qdarea[index]
    
    def GetAn(self, index:int):    #获取第index个回答资源
        if index >= self.ancount:
            print("This dns packet has only %d answers!" %(self.ancount))
            return
        return self.anarea[index]
    
    def GetNs(self, index:int):   #获取第index个权威名称服务器
        if index >= self.nscount:
            print("This dns packet has only %d authoritative nameservers!" %(self.nscount))
            return
        return self.nsarea[index]
    
    def GetAr(self, index:int):   #获取第index个附加资源
        if index >= self.arcount:
            print("This dns packet has only %d additional records!" %(self.arcount))
            return
        return self.ararea[index]
    
    def GetAnValue(self, index:int, keyy:str):  #获取第index个权威名称服务器的keyy字段
        if index >= self.ancount:
            print("This dns packet has only %d answers!" %(self.ancount))
            return
        if keyy not in self.anarea[index]:
            print("This answer does not have field: %s." %keyy)
            return
        return self.anarea[index][keyy]
    
    def GetNsValue(self, index:int, keyy:str):  #获取第index个附加资源的keyy字段
        if index >= self.nscount:
            print("This dns packet has only %d authoritative nameservers!" %(self.nscount))
            return
        if keyy not in self.nsarea[index]:
            print("This authoritative nameserver does not have field: %s." %keyy)
            return
        return self.nsarea[index][keyy]
    
    def GetArValue(self, index:int, keyy:str):  #获取第index个回答资源的keyy字段
        if index >= self.arcount:
            print("This dns packet has only %d answers!" %(self.arcount))
            return
        if keyy not in self.ararea[index]:
            print("This additional record does not have field: %s." %keyy)
            return
        return self.ararea[index][keyy]

class Icmpv4Pkt:
    def __init__(self):
        self.time = ''
        self.type_ = ''       #类型
        self.code = ''        #类型
        self.chksum = 0       #校验和，这里直接存储转换成十进制之后的值
        self.reserverd = 0
        self.length = 0
        self.nexthopmtu = 0 
        self.unused = ''
        self.IpError = {}
        self.UdpError = {}
        
    def PrintMyInfo(self):
        print("Icmpv4Info: ")
        print("time:       %s" %(self.time))
        print("type:       %s" %(self.type_))
        print("code:       %s" %(self.code))
        print("chksum:     %d" %(self.chksum))
        print("reserved:   %d" %(self.reserverd))
        print("length:     %d" %(self.length))
        if self.nexthopmtu == None:
            print("nexthopmtu: none")
        else:
            print("nexthopmtu: %d" %(self.nexthopmtu))
        print("unused:     %s" %(self.unused))
        print("IpError: ", self.IpError)
        print("UdpError: ", self.UdpError)
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'type':
            return self.type
        elif fieldname == 'code':
            return self.code
        elif fieldname == 'chksum':
            return self.chksum
        elif fieldname == 'reserved':
            return self.reserverd
        elif fieldname == 'length':
            return self.length
        elif fieldname == 'nexthopmtu':
            return self.nexthopmtu
        elif fieldname == 'unused':
            return self.unused
        elif fieldname == 'IpError':
            return self.IpError
        elif fieldname == 'UdpError':
            return self.UdpError
        else:
            print("Icmpv4Pkt does not have field named %s !" %fieldname)
    
class Icmpv6Pkt:
    def __init__(self):
        self.time = ''
        self.Icmpv6ND_RA = {}
        self.Icmpv6NDOptSrcLLAddr = {}
        self.Icmpv6NDOptMTU = {}
        self.Icmpv6NDOptPrefixInfo = {}
        
    def PrintMyInfo(self):
        print("Icmpv6Info: ")
        print("time:          %s" %(self.time))
        print("Icmpv6ND_RA: ", self.Icmpv6ND_RA)
        print("Icmpv6NDOptSrcLLAddr: ", self.Icmpv6NDOptSrcLLAddr)
        print("Icmpv6NDOptMTU: ", self.Icmpv6NDOptMTU)
        print("Icmpv6NDOptPrefixInfo: ", self.Icmpv6NDOptPrefixInfo)
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'Icmpv6ND_RA':
            return self.Icmpv6ND_RA
        elif fieldname == 'Icmpv6NDOptSrcLLAddr':
            return self.Icmpv6NDOptSrcLLAddr
        elif fieldname == 'Icmpv6NDOptMTU':
            return self.Icmpv6NDOptMTU
        elif fieldname == 'Icmpv6NDOptPrefixInfo':
            return self.Icmpv6NDOptPrefixInfo
        else:
            print("Icmpv6Pkt does not have field named %s !" %fieldname)
    
class HttpReqPkt:
    def __init__(self):
        self.time = ''
        self.method_ = ''
        self.path = ''
        self.httpVersion = ''
        self.accept = ''
        self.cacheControl = ''
        self.connection = ''
        self.contentLength = ''
        self.contentType = ''
        self.host = ''
        self.upgrade = ''
        self.userAgent = ''  #bug
        self.unknownHeaders = ''  #bug
        
    def PrintMyInfo(self):
        print("HttpReqInfo: ")
        print("time:           %s" %(self.time))
        print("method:         %s" %(self.method_))
        print("path:           %s" %(self.path))
        print("httpVersion:    %s" %(self.httpVersion))
        print("accept:         %s" %(self.accept))
        print("cacheControl:   %s" %(self.cacheControl))
        print("connection:     %s" %(self.connection))
        print("contentLength:  %s" %(self.contentLength))
        print("contentType:    %s" %(self.contentType))
        print("host:           %s" %(self.host))
        print("upgrade:        %s" %(self.upgrade))
        print("userAgent:      %s" %(self.userAgent))
        print("unknownHeaders: %s" %(self.unknownHeaders))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'method':
            return self.method_
        elif fieldname == 'path':
            return self.path
        elif fieldname == 'httpVersion':
            return self.httpVersion
        elif fieldname == 'accept':
            return self.accept
        elif fieldname == 'cacheControl':
            return self.cacheControl
        elif fieldname == 'connection':
            return self.connection
        elif fieldname == 'contentLength':
            return self.contentLength
        elif fieldname == 'contentType':
            return self.contentType
        elif fieldname == 'host':
            return self.host
        elif fieldname == 'upgrade':
            return self.upgrade
        elif fieldname == 'userAgent':
            return self.userAgent
        elif fieldname == 'unknownHeaders':
            return self.unknownHeaders
        else:
            print("HttpReqPkt does not have field named %s !" %fieldname)
        
class HttpResPkt:
    def __init__(self):
        self.time = ''
        self.httpVersion = ''
        self.statusCode = ''
        self.reasonPhrase = ''
        self.connection = ''
        self.contentLength = ''
        self.contentType = ''
        
    def PrintMyInfo(self):
        print("HttpResInfo: ")
        print("time:           %s" %(self.time))
        print("httpVersion:    %s" %(self.httpVersion))
        print("statusCode:     %s" %(self.statusCode))
        print("reasonPhrase:   %s" %(self.reasonPhrase))
        print("connection:     %s" %(self.connection))
        print("contentLength:  %s" %(self.contentLength))
        print("contentType:    %s" %(self.contentType))
        print("\n")
        
    def GetField(self, fieldname:str):
        if fieldname == 'time':
            return self.time
        elif fieldname == 'httpVersion':
            return self.httpVersion
        elif fieldname == 'statusCode':
            return self.statusCode
        elif fieldname == 'reasonPhrase':
            return self.reasonPhrase
        elif fieldname == 'connection':
            return self.connection
        elif fieldname == 'contentLength':
            return self.contentLength
        elif fieldname == 'contentType':
            return self.contentType
        else:
            print("HttpResPkt does not have field named %s !" %fieldname)

class Packet:
    def __init__(self, ethernet:EthernetPkt, ipv4:Ipv4Pkt, ipv6:Ipv6Pkt, tcp:TcpPkt,
                 udp:UdpPkt, arp:ArpPkt, dns:DnsPkt, icmpv4:Icmpv4Pkt, icmpv6:Icmpv6Pkt,
                 httpreq:HttpReqPkt, httpres:HttpResPkt):
        #self.id = -1
        self.flag = {'ethernet':0, 'ipv4':0, 'ipv6':0, 'tcp':0, 'udp':0, 'arp':0, 'dns':0,
                     'icmpv4':0, 'icmpv6':0, 'httpreq':0, 'httpres':0}
        self.ethernet = ethernet
        self.ipv4 = ipv4
        self.ipv6 = ipv6
        self.tcp = tcp
        self.udp = udp
        self.arp = arp
        self.dns = dns
        self.icmpv4 = icmpv4
        self.icmpv6 = icmpv6
        self.httpreq = httpreq
        self.httpres = httpres
        
    def PrintFlag(self):
        print(self.flag)
        
    #判断包中是否有某种协议
        
    def IsEthernet(self):
        return self.flag['ethernet']
    
    def IsIpv4(self):
        return self.flag['ipv4']
    
    def IsIpv6(self):
        return self.flag['ipv6']
    
    def IsTcp(self):
        return self.flag['tcp']
    
    def IsUdp(self):
        return self.flag['udp']
    
    def IsArp(self):
        return self.flag['arp']
    
    def IsDns(self):
        return self.flag['dns']
    
    def IsIcmpv4(self):
        return self.flag['icmpv4']
    
    def IsIcmpv6(self):
        return self.flag['icmpv6']
    
    def IsHttpReq(self):
        return self.flag['httpreq']
    
    def IsHttpRes(self):
        return self.flag['httpres']
    
    #获取某种协议类
    
    def GetEthernet(self):
        if self.flag['ethernet']:
            return self.ethernet
        else:
            print("This packet does not have ethernet!")
    
    def GetIpv4(self):
        if self.flag['ipv4']:
            return self.ipv4
        else:
            print("This packet does not have ipv4!")
            return 0
    
    def GetIpv6(self):
        if self.flag['ipv6']:
            return self.ipv6
        else:
            print("This packet does not have ipv6!")
            return 0
    
    def GetTcp(self):
        if self.flag['tcp']:
            return self.tcp
        else:
            print("This packet does not have tcp!")
            return 0
    
    def GetUdp(self):
        if self.flag['udp']:
            return self.udp
        else:
            print("This packet does not have udp!")
            return 0
    
    def GetArp(self):
        if self.flag['arp']:
            return self.arp
        else:
            print("This packet does not have arp!")
            return 0
    
    def GetDns(self):
        if self.flag['dns']:
            return self.dns
        else:
            print("This packet does not have dns!")
            return 0
    
    def GetIcmpv4(self):
        if self.flag['icmpv4']:
            return self.icmpv4
        else:
            print("This packet does not have icmpv4!")
            return 0
    
    def GetIcmpv6(self):
        if self.flag['icmpv6']:
            return self.icmpv6
        else:
            print("This packet does not have icmpv6!")
            return 0
    
    def GetHttpReq(self):
        if self.flag['httpreq']:
            return self.httpreq
        else:
            print("This packet does not have httpreq!")
            return 0
    
    def GetHttpRes(self):
        if self.flag['httpres']:
            return self.httpres
        else:
            print("This packet does not have httpres!")
            return 0